/**
 ******************************************************************************
 * @文件名称 : task_dataRW.c
 * @摘要 :
 * @创建日期 : Jul 31, 2024
 * @创建者：MBL
 ******************************************************************************
 * @使用说明
 *
 *
 ******************************************************************************
 */

/* 声明包含头文件 -----------------------------------------------------------*/

#include "../Inc/task_dataRW.h"
#include "stdbool.h"

/* 声明私有类型定义---------------------------------------------------------*/
typedef enum
{
	WRITE_NAND_ALARM,	// 写报警数据
	WRITE_NAND_RUN,		// 写运行数据
	WRITE_NAND_OTHER,   // 写其他（字库、图库、屏幕、）
	READ_NAND_ALARM,    // 读报警数据
	READ_NAND_CURVE,	// 读曲线数据
	READ_NAND_PACK,		// 读分包数据
	READ_NAND_OTHER,	// 读其他（字库、图库、屏幕、）
}NAND_OPT_Type;
/* 声明私有变量 -------------------------------------------------------------*/
static FATFS nandFs;
static FIL nandFile;
static FIL nandRunFile;
/* 声明私有常量 -------------------------------------------------------------*/

static TCHAR *nandPath[] = {
		"0:run.bin",			// 设备运行信息路径
		"0:screenFlag.bin",		// 屏幕辅助标志位路径
		"0:screenParam.bin",	// 屏幕参数信息路径
		"0:alarm.bin",			// 设备报警信息路径
		"0:font.bin",			// 字体存储路径
		"0:img_start.bin",  	    // 开机图片路径
		"0:img_main.bin",    	    // 主界面图片路径
		"0:img_back.bin",           // 背景图片路径
		"0:img_maininter.bin",      // 主界面内框图片路径
		"0:img_about.bin",          // 关于本机图标
		"0:ico_curve.bin",	        // 曲线图标
		"0:ico_menu.bin",           // 菜单图标
		"0:ico_menuon.bin",	 		// 菜单按钮选中图标
		"0:ico_menuoff.bin",        // 菜单按钮释放图标
		"0:ico_mess.bin",	        // 消息图标
		"0:ico_messon.bin",	        // 消息选中图标
		"0:ico_messoff.bin", 		// 消息未选中图标
		"0:ico_run.bin",            // 运行图标
		"0:ico_stop.bin",	        // 停止图标
		"0:ico_sidebaron.bin",	    // 侧边栏选中图标
		"0:ico_sidebaroff.bin",     // 侧边栏释放图标
		"0:ico_temp.bin",	        // 温度图标
		"0:ico_tempbig.bin",	    // 温度大图标
		"0:ico_toggle.bin",	        // 切换图标
		"0:ico_luck.bin",           // 吉祥物图标
		"0:ico_logo.bin"			// LOGO图标
};
/* 声明私有宏定义 -----------------------------------------------------------*/
#define NAND_MATERIAL_CNT           (22)
#define RUN_RECORD_MAX_COUNT	    (86400 * sizeof(CD))		  // 运行文件最大大小(不包含读写指针大小)
#define RUN_RW_SKEW_SIZE            (4)                           // 读写指针的大小
/* 声明私有函数 -------------------------------------------------------------*/

/**
  * @brief	检查NAND中字库、素材是否存在
  * @param  None
  * @retval TRUE : NAND完整   FALSE: NAND数据不完整
  */
static bool check_NAND(void)
{
	FRESULT res;
	FILINFO fno;
	uint8_t paramOkCont = 0;		// 存在参数数量

	for (uint8_t i = 0; i < NAND_MATERIAL_CNT; i++)		// 循环判断路径是否完整
	{
		res = f_stat(nandPath[i+4], &fno);
		if (res == FR_OK)
		{
			paramOkCont++;
		}
	}
	if (paramOkCont == NAND_MATERIAL_CNT)
	{
		return true;
	}
	printf("Failed to read media!!!");
	return false;
}
/**
 * @brief  向NAND中写入数据
 * @param  type：当前操作类型 path：写路径	 data；写缓冲 size：写入的记录大小
 * @retval 无
 */
static void fatfs_writeNand(NAND_OPT_Type type, char * path, void * data, uint32_t size)
{
	UINT bw,br;
	FRESULT res;

	if (type == WRITE_NAND_ALARM)
	{
		info_t info;
		listNode_t * head = (listNode_t *)data;
		res = f_open(&nandFile, path, FA_WRITE | FA_CREATE_ALWAYS);//todo:为什么用FA_CREATE_ALWAYS
		if (res == FR_OK)
		{
			while (head != NULL)
			{
				info = head->record;
				res = f_write(&nandFile, &info, size, &bw);
				head = head->next;
			}
			f_close(&nandFile);
		}
	}
	else if (type == WRITE_NAND_RUN)
	{
		int WriteSkew = 0;			        // 写指针
		res = f_open(&nandRunFile, path, FA_OPEN_ALWAYS| FA_WRITE | FA_READ);
		/* 获取写指针 */
		if (res == FR_OK)
		{
			res = f_read(&nandRunFile,&WriteSkew, sizeof(WriteSkew), &br);
			if (WriteSkew < RUN_RECORD_MAX_COUNT)
			{
				res = f_lseek(&nandRunFile, WriteSkew + RUN_RW_SKEW_SIZE);
				res = f_write(&nandRunFile, (struct chartData*)data, size, &bw);
//				printf("Skew: %d  \n", WriteSkew);
				WriteSkew += size;
			}
			else
			{
				WriteSkew = 0;
				res = f_lseek(&nandRunFile, RUN_RW_SKEW_SIZE);
				res = f_write(&nandRunFile, (struct chartData*)data, size, &bw);
				WriteSkew += size;
			}
			/* 将读写指针写入文件 */
			res = f_lseek(&nandRunFile, 0);
			res = f_write(&nandRunFile, &WriteSkew, sizeof(WriteSkew), &bw);
//			printf("Skew: %d  \n", WriteSkew);
			f_close(&nandRunFile);
		}
	}
	else if (type == WRITE_NAND_OTHER)
	{

		res = f_open(&nandFile, path, FA_WRITE | FA_CREATE_ALWAYS);
		if (res == FR_OK)
		{
			res = f_write(&nandFile, data, size, &bw);
			f_close(&nandFile);
		}
	}
}
/**
 * @brief  从NAND中读取数据
 * @param  type：当前操作类型 path：读路径	 data；读缓冲 size：读大小
 * @retval None
 */
static void fatfs_readNand(NAND_OPT_Type type, char * path, void * data, uint32_t size)
{
	UINT br;
	FRESULT res;

	if (type == READ_NAND_ALARM)
	{
		info_t info;
//		listNode_t * head = NULL;
		res = f_open(&nandFile, path, FA_READ);
		if (res == FR_OK)
		{
			res = f_read(&nandFile, &info, size, &br);
			while (br == size)
			{
//				list_addTailNode(&head, info);
				if(++historyInfoNodeQty > HISTORY_INFO_DISP_QTY_MAX)
				{
					historyInfoNodeQty--;
					break;
				}
				list_addTailNode(&listNode_historyInfo, info);
				res = f_read(&nandFile, &info, size, &br);
			}
//			listNode_historyInfo = head;  //listNode_historyInfo
		}

	}
	else if (type == READ_NAND_CURVE)
	{
		int curveSkew = 0;
		int curveSize = 0;
		res = f_open(&nandFile, path, FA_READ);
		/* 获取文件总大小 */
		curveSize = f_size(&nandFile);
		/* 获取读写指针 */
		if (res == FR_OK)
		{
			res = f_read(&nandFile, &curveSkew, sizeof(curveSkew), &br);
		}
		if (curveSkew == curveSize - RUN_RW_SKEW_SIZE)  // 文件未写满
		{
			if (curveSkew <= size)		                // 不足一包数据，全部读出
			{
				res = f_read(&nandFile, (struct chartData*)data, size, &br);
			}
			else								        // 超过一包，移动指针读取
			{
				res = f_lseek(&nandFile, curveSkew -size + RUN_RW_SKEW_SIZE);
				res = f_read(&nandFile, (struct chartData*)data, size, &br);
			}
		}
		else   // 文件已经写满
		{
			if (curveSkew <= size)
			{
				res = f_lseek(&nandFile, RUN_RECORD_MAX_COUNT - (size - curveSkew) + RUN_RW_SKEW_SIZE );// 读取尾部剩余数据
				res = f_read(&nandFile, (struct chartData*)data, size - curveSkew, &br);
				res = f_lseek(&nandFile, RUN_RW_SKEW_SIZE );// 读取头部剩余数据
				res = f_read(&nandFile, (struct chartData*)data + \
						(size - curveSkew)/sizeof(struct chartData), curveSkew, &br);
			}
			else
			{
				res = f_lseek(&nandFile, curveSkew - size + RUN_RW_SKEW_SIZE);
				res = f_read(&nandFile, (struct chartData*)data, size, &br);
			}
		}
	}
	else if (type == READ_NAND_PACK)
	{
		int packSkew = 0;
		int packSize = 0;
		res = f_open(&nandFile, path, FA_READ);
		/* 获取文件总大小 */
		packSize = f_size(&nandFile);
		/* 获取读写指针 */
		if (res == FR_OK)
		{
			res = f_read(&nandFile, &packSkew, sizeof(packSkew), &br);
		}
		if (packSkew == packSize - RUN_RW_SKEW_SIZE)  // 文件未写满
		{
			if (packSkew <= size)		// 不足一包数据，全部读出
			{
				res = f_read(&nandFile, (struct chartData*)data, size, &br);
				g_packCount =  br / sizeof(struct chartData);
				g_packReadOK = 2;		// 读取完成
			}
			else								// 超过一包，分批次读取
			{
				if (g_packRW < packSkew)
				{
					res = f_lseek(&nandFile, g_packRW + RUN_RW_SKEW_SIZE);
					res = f_read(&nandFile, (struct chartData*)data, size, &br);
					g_packRW += br;
					g_packCount =  br / sizeof(struct chartData);
				}
				else
				{
					g_packCount = 0;
					g_packReadOK = 2;
				}

			}
		}
		else   // 文件已经写满
		{
			if (g_packRW < packSize - RUN_RW_SKEW_SIZE - packSkew)  // 读取WriteSkew到文件结尾
			{
				res = f_lseek(&nandFile, g_packRW + packSkew + RUN_RW_SKEW_SIZE);
				res = f_read(&nandFile, (struct chartData*)data, \
						size, &br);
				g_packRW += br;
				g_packCount =  br / sizeof(struct chartData);
			}
			else  // 读取文件头部到WriteSkew之间
			{
				res = f_lseek(&nandFile, g_packRW - \
						(packSize - RUN_RW_SKEW_SIZE - packSkew) + RUN_RW_SKEW_SIZE);
				if (g_packRW < packSize - RUN_RW_SKEW_SIZE)
				{
					if (packSize - RUN_RW_SKEW_SIZE - g_packRW >= size) // 超过一包数据
					{
						res = f_read(&nandFile, (struct chartData*)data, size, &br);
					}
					else
					{
						res = f_read(&nandFile, (struct chartData*)data, \
								packSize - RUN_RW_SKEW_SIZE - g_packRW, &br);
					}
					g_packRW += br;
					g_packCount =  br / sizeof(struct chartData);
				}
				else
				{
					g_packCount = 0;
					g_packReadOK = 2;
				}
			}
		}
		f_close(&nandFile);
	}
	else if(type == READ_NAND_OTHER)
	{
		res = f_open(&nandFile, path, FA_READ);
		if (res == FR_OK)
		{
			res = f_read(&nandFile, data, size, &br);
			f_close(&nandFile);
		}

	}
}

/**
  * @brief	挂载NAND
  * @param  None
  * @retval None
  */
static void mount_NAND(void)
{
	FRESULT res;
//	BYTE work[FF_MAX_SS];
	FILINFO fno;
	DIR dir;
	FATFS *fs;
	DWORD fre_clust, fre_sect, tot_sect;
//	nand_erasechip();
//	ftl_init();		         /* 初始化FTL分区 */
	res = f_mount(&nandFs, "0:", 1);                   /* 挂载NAND FLASH. */

//	if (res == FR_NO_FILESYSTEM)
//	{
//		res = f_mkfs("0:", 0, work, sizeof(work));     /* 格式化NAND */
//		res = f_setlabel((const TCHAR *)"0:NANDDISK");
//		res = f_mount(&nandFs, "0:", 1);               /* 挂载NAND FLASH. */
//	}
	if (res == FR_OK)
	{
		g_mountNand_flag = 1;
	}
	/* Get total sectors and free sectors */
	res = f_getfree("0:", &fre_clust, &fs);
	tot_sect = (fs->n_fatent - 2) * fs->csize;
	fre_sect = fre_clust * fs->csize;

	tot_sect /= 2; // 假设扇区大小为512字节，除以2得到Kbyte
	fre_sect /= 2; // 假设扇区大小为512字节，除以2得到Kbyte

	// 打印结果
	printf("Total size: %lu Mbytes\r\n", tot_sect);
	printf("Free size: %lu Mbytes\r\n", fre_sect);

	res = f_opendir(&dir, "0:");
	if (res == FR_OK) {
	    int i = 0;

	    // 循环读取目录项
	    while (1) {
	        res = f_readdir(&dir, &fno);
	        if (res != FR_OK || fno.fname[0] == 0) {
	            break;
	        }

	        // 打印文件或目录信息
	        printf("%s (%lu bytes)\r\n", fno.fname, (DWORD)fno.fsize);
	        i++;
	    }

	    // 关闭目录
	    f_closedir(&dir);
	}
}

/**
  * @brief	读nandflash业务逻辑层
  * @param  task 本任务控制结构体
  * @retval None
  */
int bll_dataRW(struct task_pcb *task)
{

//	if (g_mountNand_flag != 1)
//	{
//		mount_NAND();
//	}
	/* 读取NANDFLASH */
	if (task->event & TASK5_EVENT1_NAND_MATERIAL_READ)  // 读素材
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		if (check_NAND())
		{
			fatfs_readNand(READ_NAND_OTHER, nandPath[4], g_fontBuff, sizeof(g_fontBuff));
			for (uint8_t i = 0; i < 5; i++)
			{
				fatfs_readNand(READ_NAND_OTHER, nandPath[5 + i], g_imgBuff[i], sizeof(g_imgBuff[i]));
			}
			for (uint8_t i = 0; i < 16; i++)
			{
				fatfs_readNand(READ_NAND_OTHER, nandPath[10 + i], g_icoBuff[i], sizeof(g_icoBuff[i]));
			}
		}

		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT1_NAND_MATERIAL_READ);
	}
	if (task->event & TASK5_EVENT1_NAND_SCREEN_READ)    // 读屏幕参数
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_readNand(READ_NAND_OTHER, nandPath[1], &DA, sizeof(DA));	// 读取屏幕标志位
		fatfs_readNand(READ_NAND_OTHER, nandPath[2], &DS, sizeof(DS));	// 读取屏幕参数
		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT1_NAND_SCREEN_READ);
	}
	if (task->event & TASK5_EVENT1_NAND_CURVE_READ)
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_readNand(READ_NAND_CURVE, nandPath[0], curveData, sizeof(curveData)); // 读曲线数据
		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT1_NAND_CURVE_READ);
	}
	if (task->event & TASK5_EVENT1_NAND_PACK_READ)// 读取USB一包数据
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_readNand(READ_NAND_PACK, nandPath[0], g_packBuff, sizeof(g_packBuff)); // 读USB数据
		g_RW_State = RW_WRITE_USB_DATA;
		task->event &= (~TASK5_EVENT1_NAND_PACK_READ);
	}
	if (task->event & TASK5_EVENT1_NAND_ALARM_READ)
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_readNand(READ_NAND_ALARM, nandPath[3], listNode_historyInfo, sizeof(info_t));// 读取报警数据
		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT1_NAND_ALARM_READ);
	}
	/* 写入NANDFLASH */
	if (task->event & TASK5_EVENT2_NAND_MATERIAL_WRITE)     // 写素材
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_writeNand(WRITE_NAND_OTHER, nandPath[4], g_fontBuff, sizeof(g_fontBuff));

		for (uint8_t i = 0; i < 5; i++)
		{
			fatfs_writeNand(WRITE_NAND_OTHER, nandPath[5 + i], g_imgBuff[i], sizeof(g_imgBuff[i]));
		}
		for (uint8_t i = 0; i < 16; i++)
		{
			fatfs_writeNand(WRITE_NAND_OTHER, nandPath[10 + i], g_icoBuff[i], sizeof(g_icoBuff[i]));
		}

		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT2_NAND_MATERIAL_WRITE);
	}
	if (task->event & TASK5_EVENT2_NAND_SCREEN_WRITE)		// 写屏幕
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_writeNand(WRITE_NAND_OTHER, nandPath[1], &DA, sizeof(DA));	// 写入屏幕标志位
		fatfs_writeNand(WRITE_NAND_OTHER, nandPath[2], &DS, sizeof(DS));	// 写入屏幕参数
		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT2_NAND_SCREEN_WRITE);
	}
	if (task->event & TASK5_EVENT2_NAND_RUN_WRITE)
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		CD.chartTime = DS.clockTime;
		CD.tempSV = UP.SV_Temp1;
		CD.tempPV1 = UP.mainTempDisplay;
		CD.tempPV2 = UP.subTempDisplay;
		CD.pressSV = UP.SV_Temp1;
		CD.flowPV = UP.flowDisplay;
		CD.flowSV = UP.SV_Flow;
		CD.pressPV1 = UP.outPressDisplay;
		CD.pressPV2 = UP.inPressDisplay;
		CD.pressSV = UP.SV_Press;
		fatfs_writeNand(WRITE_NAND_RUN, nandPath[0], &CD, sizeof(CD));      // 写运行数据
		task->event &= (~TASK5_EVENT2_NAND_RUN_WRITE);
	}
	if (task->event & TASK5_EVENT2_NAND_ALARM_WRITE)
	{
		if (g_mountNand_flag != 1)
		{
			mount_NAND();
		}
		fatfs_writeNand(WRITE_NAND_ALARM, nandPath[3], listNode_historyInfo, sizeof(info_t));// 写报警记录
		g_RW_State = RW_READY;
		task->event &= (~TASK5_EVENT2_NAND_ALARM_WRITE);
	}
  return 0;
}

